package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.account.AccountLockResultVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //  获取当前用户对象：
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        //  计算金额
        //  订单原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
        //  订单明细集合
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //  订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //  判断是否购买专辑 1001
        if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
            // 此处代码省略....

            //  购买声音
        } else if (tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)) {
            //  判断
            if (tradeVo.getTrackCount().intValue() < 0) {
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            //  获取下单声音列表
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            //  购买声音不支持折扣
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            AlbumInfo albumInfo = albumInfoResult.getData();
            originalAmount = tradeVo.getTrackCount().intValue() > 0 ? albumInfo.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount())) : albumInfo.getPrice();
            //  计算订单总价
            orderAmount = originalAmount;

            //  循环遍历声音集合对象赋值订单明细
            orderDetailVoList = trackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                return orderDetailVo;
            }).collect(Collectors.toList());
        } else {
            // 此处代码省略....

        }
        // 防重：生成一个唯一标识，保存到redis中一份
        String tradeNoKey = "user:trade:" + userId;
        // 定义一个流水号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);

        //构造结果
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        // 默认选择微信支付
        orderInfoVo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);
        return orderInfoVo;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //  校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay", SystemConstant.ORDER_PAY_WAY_WEIXIN);
        SignHelper.checkSign(map);

        //  验证校验好，防止重复提交订单
        String tradeNo = orderInfoVo.getTradeNo();
        if (StringUtils.isEmpty(tradeNo)) {
            //  非法提交
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        String tradeNoKey = "user:trade:" + userId;
        String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(tradeNoKey), tradeNo);
        if (!flag) {
            // 不能重复提交订单！
            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }
        //  3.下单
        //  使用交易号座位订单号，或者重新生成订单号
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        //  支付类型
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            //  在线支付
            this.saveOrder(orderInfoVo, userId, orderNo);
        } else {
            try {
                //  余额支付
                //  锁定账户可用金额
                AccountDeductVo accountDeductVo = new AccountDeductVo();
                accountDeductVo.setOrderNo(orderNo);
                accountDeductVo.setUserId(userId);
                accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
                accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
                //  检查与锁定账户金额
                Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
                if (200 != result.getCode()) {
                    throw new GuiguException(result.getCode(), result.getMessage());
                }
                //  保存订单
                OrderInfo orderInfo = this.saveOrder(orderInfoVo, userId, orderNo);
                //  创建用户购买记录对象
                UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
                //  记录用户购买信息
                userPaidRecordVo.setOrderNo(orderNo);
                userPaidRecordVo.setUserId(orderInfo.getUserId());
                userPaidRecordVo.setItemType(orderInfo.getItemType());
                //  购买项目的Id 专辑Id，声音Id, 服务配置Id: 在哪? order_detail.item_id
                List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
                userPaidRecordVo.setItemIdList(itemIdList);
                //  远程调用：
                Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
                //  判断
                if (200 != userResult.getCode()) {
                    throw new GuiguException(211, "新增购买记录异常");
                }
                //  返回订单编号
                return orderNo;

            } catch (GuiguException e) {
                e.printStackTrace();
                //抛出异常
                throw new GuiguException(e.getCode(), e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
                //抛出异常
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }
        }
        return orderNo;
    }

    @Transactional
    @Override
    public OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //  创建对象对象
        OrderInfo orderInfo = new OrderInfo();
        //  属性拷贝
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setOrderNo(orderNo);
        String orderTitle = orderInfoVo.getOrderDetailVoList().get(0).getItemName();
        orderInfo.setOrderTitle(orderTitle);
        orderInfo.setUserId(userId);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //  保存订单
        orderInfoMapper.insert(orderInfo);

        // 订单明细
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDetailVoList())) {
            orderInfoVo.getOrderDetailVoList().forEach(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            });
        }

        // 订单减免
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDerateVoList())) {
            orderInfoVo.getOrderDerateVoList().forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            });
        }

        // 订单支付方式 1101-微信 1102-支付宝 1103-账户余额
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay())) {
            // 余额支付成功保存交易数据
            this.orderPaySuccess(orderNo);
        } else {
            // 发送延迟队列，如果定时未支付，取消订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER, MqConst.ROUTING_CANCEL_ORDER, orderInfo.getId(), MqConst.CANCEL_ORDER_DELAY_TIME);
        }
        // 返回订单信息
        return orderInfo;
    }

    @Override
    public void orderPaySuccess(String orderNo) {
        //  查询对象
        //  OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        //  如果已经修改为支付，那么就不需要再修改了.
        if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID)){
            return;
        }
        //  赋值为已支付
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        //  修改状态
        this.updateById(orderInfo);
        //  记录用户购买信息: 微信支付就需要再次调用；余额支付不需要！
        if (orderInfo.getPayWay().equals(SystemConstant.ORDER_PAY_WAY_WEIXIN)){
            //  添加一个判断：
            //  保存用户购买记录：
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setUserId(orderInfo.getUserId());
            userPaidRecordVo.setItemType(orderInfo.getItemType());
            //  [专辑Id;vip服务配置Id;下单的时候只能购买一个，这个明细数据就是一条] 声音Id{应该是集合}
            //  以上Id都在? orderInfoVo.getOrderDetailVoList(); 订单明细表中有itemId;
            //  List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            //  声音只支持余额支付！
            List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);
            //  远程调用保存用户交易记录。
            this.userInfoFeignClient.savePaidRecord(userPaidRecordVo);
        }

    }

    //根据订单orderNo 获取订单对象
    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //  获取订单对象
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        //  查看订单明细
        List<OrderDetail> orderDetailList = orderDetailMapper
                .selectList(new LambdaQueryWrapper<OrderDetail>()
                        .eq(OrderDetail::getOrderId, orderInfo.getId()));

        // 赋值订单明细
        orderInfo.setOrderDetailList(orderDetailList);

        orderInfo.setPayWayName(this.getPayWayName(orderInfo.getPayWay()));
        // 返回数据
        return orderInfo;
    }

    //根据payWay 返回支付名称
    private String getPayWayName(String payWay) {
        //  声明一个对象
        return SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)?"微信支付":"余额支付";
    }

    @Override
    public void orderCancel(Long orderId) {
        // 设置更新数据
        OrderInfo orderInfoUpt = new OrderInfo();
        orderInfoUpt.setId(orderId);
        orderInfoUpt.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        // 执行更新方法
        this.updateById(orderInfoUpt);
    }

    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> pageParam, Long userId) {
        //  调用mapper 层方法
        IPage<OrderInfo> infoIPage = orderInfoMapper.selectUserPage(pageParam,userId);
        infoIPage.getRecords().forEach(item->{
            //  设置状态名
            item.setOrderStatusName(getOrderStatusName(item.getOrderStatus()));
            item.setPayWayName(getPayWayName(item.getPayWay()));
        });
        return infoIPage;
    }

    //  根据订单状态获取到订单名称
    private String getOrderStatusName(String orderStatus) {
        //  声明订单状态名称
        String orderStatusName = "";
        //  判断
        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)){
            orderStatusName = "未支付";
        } else if (SystemConstant.ORDER_STATUS_PAID.equals(orderStatus)) {
            orderStatusName = "已支付";
        } else {
            orderStatusName = "已取消";
        }
        //  返回
        return orderStatusName;
    }

}
